package com.xf.oss.http;

import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.Bucket;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.s3.model.S3ObjectSummary;
import com.xf.oss.service.OssTemplate;
import lombok.AllArgsConstructor;
import lombok.Cleanup;
import lombok.SneakyThrows;
import org.springframework.http.HttpStatus;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.InputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 对外提供接口
 *
 * @author xufeng
 */
@Validated
@RestController
@AllArgsConstructor
@RequestMapping("${oss.http.prefix:}/oss")
public class OssEndpoint {

    private final OssTemplate template;

    /**
     * 创建存储桶
     * 推荐 应用/userID/日期
     */
    @SneakyThrows
    @PostMapping("/bucket/{bucketName}")
    public Bucket createBucket(@PathVariable @NotBlank String bucketName) {

        template.createBucket(bucketName);
        return template.getBucket(bucketName).orElse(null);

    }

    /**
     * 获取桶列表
     *
     * @return
     */
    @SneakyThrows
    @GetMapping("/bucket")
    public List<Bucket> getBuckets() {
        return template.getAllBuckets();
    }

    /**
     * 获取桶信息
     *
     * @param bucketName 存储桶
     * @return
     */
    @SneakyThrows
    @GetMapping("/bucket/{bucketName}")
    public Bucket getBucket(@PathVariable @NotBlank String bucketName) {
        return template.getBucket(bucketName).orElseThrow(() -> new IllegalArgumentException("Bucket Name not found!"));
    }

    /**
     * 删除桶信息
     *
     * @param bucketName
     */
    @SneakyThrows
    @DeleteMapping("/bucket/{bucketName}")
    @ResponseStatus(HttpStatus.ACCEPTED)
    public void deleteBucket(@PathVariable @NotBlank String bucketName) {
        template.removeBucket(bucketName);
    }

    /**
     * 上传文件 原始名称
     *
     * @param object     文件地址
     * @param bucketName 桶地址
     * @return
     */
    @SneakyThrows
    @PostMapping("/object/{bucketName}")
    public S3Object createObject(@RequestBody MultipartFile object, @PathVariable @NotBlank String bucketName) {

        String name = object.getOriginalFilename();
        template.putObject(bucketName, name, object.getInputStream(), object.getSize(), object.getContentType());
        return template.getObjectInfo(bucketName, name);

    }

    /**
     * 获取临时上传url地址 适用于前端上传
     *
     * @param bucketName 桶地址
     * @param objectName 自定义文件名称
     * @param minutes    过期时间，单位分钟,请注意该值必须小于7天
     * @return {@link String} 返回临时上传url
     */
    @SneakyThrows
    @PostMapping("/object/{bucketName}/{objectName}")
    public String createObject(@PathVariable @NotBlank String bucketName,
                               @PathVariable @NotBlank String objectName, int minutes) {

        return template.getPutObjectURL(bucketName, objectName, minutes);

    }

    /**
     * 由服务端上传文件
     * 占用服务器带宽，不推荐
     *
     * @param object     文件地址
     * @param bucketName 桶地址
     * @param objectName 自定义文件名称
     * @return
     */
    @SneakyThrows
    @PostMapping("/objectSummary/{bucketName}/{objectName}")
    public S3ObjectSummary createObjectSummary(@RequestBody @NotNull MultipartFile object,
                                               @PathVariable @NotBlank String bucketName, @PathVariable @NotBlank String objectName) {
        @Cleanup
        InputStream inputStream = object.getInputStream();
        template.putObject(bucketName, objectName, inputStream, object.getSize(), object.getContentType());
        S3Object objectInfo = template.getObjectInfo(bucketName, objectName);
        ObjectMetadata objectMetadata = objectInfo.getObjectMetadata();
        S3ObjectSummary objectSummary = new S3ObjectSummary();
        objectSummary.setKey(objectInfo.getKey());
        objectSummary.setBucketName(bucketName);
        objectSummary.setETag(objectMetadata.getETag());
        objectSummary.setLastModified(objectMetadata.getLastModified());
        objectSummary.setSize(objectMetadata.getContentLength());
        return objectSummary;
    }

    /**
     * 根据文件前缀查询匹配数据
     *
     * @param bucketName 桶地址
     * @param objectName 文件前缀
     * @return
     */
    @SneakyThrows
    @GetMapping("/object/{bucketName}/{objectName}")
    public List<S3ObjectSummary> filterObject(@PathVariable @NotBlank String bucketName,
                                              @PathVariable @NotBlank String objectName) {

        return template.getAllObjectsByPrefix(bucketName, objectName);

    }

    /**
     * 获取文件外链，只用于下载
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param expires    过期时间，单位分钟,请注意该值必须小于7天
     * @return url
     * @see AmazonS3#generatePresignedUrl(String bucketName, String key, Date expiration)
     */
    @SneakyThrows
    @GetMapping("/object/{bucketName}/{objectName}/{expires}")
    public Map<String, Object> getObject(@PathVariable @NotBlank String bucketName,
                                         @PathVariable @NotBlank String objectName,
                                         @PathVariable @NotNull Integer expires) {

        Map<String, Object> responseBody = new HashMap<>(8);
        // Put Object info
        responseBody.put("bucket", bucketName);
        responseBody.put("object", objectName);
        responseBody.put("url", template.getObjectURL(bucketName, objectName, expires));
        responseBody.put("expires", expires);
        return responseBody;
    }

    /**
     * 删除文件
     *
     * @param bucketName 桶地址
     * @param objectName 文件地址
     */
    @SneakyThrows
    @ResponseStatus(HttpStatus.ACCEPTED)
    @DeleteMapping("/object/{bucketName}/{objectName}/")
    public void deleteObject(@PathVariable @NotBlank String bucketName, @PathVariable @NotBlank String objectName) {

        template.removeObject(bucketName, objectName);
    }

}